package com.chatplus.application.service.account.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chatplus.application.common.logging.SouthernQuietLogger;
import com.chatplus.application.common.logging.SouthernQuietLoggerFactory;
import com.chatplus.application.dao.account.UserDao;
import com.chatplus.application.dao.account.UserProductLogDao;
import com.chatplus.application.dao.basedata.ProductDao;
import com.chatplus.application.domain.entity.account.UserEntity;
import com.chatplus.application.domain.entity.account.UserProductLogEntity;
import com.chatplus.application.domain.entity.basedata.ProductEntity;
import com.chatplus.application.domain.notification.PowerLogNotification;
import com.chatplus.application.enumeration.AiPlatformEnum;
import com.chatplus.application.enumeration.FundTypeEnum;
import com.chatplus.application.enumeration.PowerLogTypeEnum;
import com.chatplus.application.enumeration.ProductTypeEnum;
import com.chatplus.application.service.account.UserProductLogService;
import com.chatplus.application.util.ConfigUtil;
import com.chatplus.application.web.notification.NotificationPublisher;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

/**
 * 用户套餐记录业务逻辑实现
 *
 * <p>Table: t_user_product_log - 用户套餐记录</p>
 *
 * @author developer
 * @see UserProductLogEntity
 */
@Service
public class UserProductLogServiceImpl extends ServiceImpl<UserProductLogDao, UserProductLogEntity> implements UserProductLogService {
    private static final SouthernQuietLogger LOGGER = SouthernQuietLoggerFactory.getLogger(UserProductLogServiceImpl.class);

    private final ProductDao productDao;
    private final UserDao userDao;

    private final NotificationPublisher notificationPublisher;

    public UserProductLogServiceImpl(ProductDao productDao, UserDao userDao, NotificationPublisher notificationPublisher) {
        this.productDao = productDao;
        this.userDao = userDao;
        this.notificationPublisher = notificationPublisher;
    }

    @Override
    public void addProductToUser(Long userId, Long productId, Long orderId) {
        ProductEntity productEntity = productDao.selectById(productId);
        if (productEntity == null) {
            LOGGER.message("套餐不存在")
                    .context("userId", userId)
                    .context("productId", productId)
                    .context("orderId", orderId)
                    .error();
            return;
        }
        UserEntity userEntity = userDao.selectById(userId);
        if (userEntity == null) {
            LOGGER.message("用户不存在")
                    .context("userId", userId)
                    .context("productId", productId)
                    .context("orderId", orderId)
                    .error();
            return;
        }
        ProductTypeEnum productType = productEntity.getProductType();
        PowerLogNotification powerLogNotification = new PowerLogNotification();
        powerLogNotification.setUserId(userId);
        powerLogNotification.setType(PowerLogTypeEnum.PAY);
        powerLogNotification.setMark(FundTypeEnum.INCOME);
        switch (productType) {
            case TIME_CARD:
                Integer power = productEntity.getPower();
                UserProductLogEntity userProductLogEntity = new UserProductLogEntity();
                userProductLogEntity.setUserId(userId);
                userProductLogEntity.setProductId(productId);
                userProductLogEntity.setOrderId(orderId);
                userProductLogEntity.setPower(power);
                userProductLogEntity.setProductType(ProductTypeEnum.TIME_CARD);
                userProductLogEntity.setSubsStartTime(Instant.now());
                if (productEntity.getDays() > 0) {
                    // 有时效的次卡
                    userProductLogEntity.setSubsEndTime(Instant.now().plus(productEntity.getDays(), ChronoUnit.DAYS));
                } else {
                    // 无时效的次卡 - 默认有效期100年
                    userProductLogEntity.setSubsEndTime(Instant.now().plus(36500, ChronoUnit.DAYS));
                }
                super.save(userProductLogEntity);

                powerLogNotification.setAmount(productEntity.getPower());
                String endDate = DateUtil.format(Date.from(userProductLogEntity.getSubsEndTime()), DatePattern.CHINESE_DATE_PATTERN);
                powerLogNotification.setRemark(String.format(String.format("充值次卡, 算力：%d，有效期至：%s", power, endDate)));
                break;
            case SUBSCRIPTION_CARD:
                // vip延长有效期
                Instant vipExpiredTime = userEntity.getVipExpiredTime();
                Instant now = Instant.now();

                if (vipExpiredTime == null || vipExpiredTime.isBefore(now)) {
                    vipExpiredTime = now;
                    userEntity.setVipResetDate(DateUtil.format(
                            Date.from(now.plus(1, ChronoUnit.DAYS)),
                            DatePattern.NORM_DATE_PATTERN));
                    resetSubscribeToUserByDaily(userId, null);
                }
                userEntity.setVipExpiredTime(vipExpiredTime.plus(productEntity.getDays(), ChronoUnit.DAYS));
                userDao.updateById(userEntity);
                String endSubDate = DateUtil.format(Date.from(userEntity.getVipExpiredTime()), DatePattern.CHINESE_DATE_PATTERN);
                powerLogNotification.setRemark(String.format(String.format("充值日卡, 会员有效期至：%s", endSubDate)));
                break;
            default:
                LOGGER.message("不支持的套餐类型")
                        .context("userId", userId)
                        .context("productId", productId)
                        .context("orderId", orderId)
                        .context("productType", productType)
                        .error();
                break;
        }
        if (StringUtils.isNotEmpty(powerLogNotification.getRemark())) {
            notificationPublisher.publish(powerLogNotification);
        }
    }

    @Override
    public void adminAddPowerToUser(Long userId, Integer power, String remark) {
        if (power == 0) {
            return;
        }
        if (StringUtils.isEmpty(remark)) {
            remark = "系统操作";
        }
        handlePower(userId, power);
        PowerLogNotification powerLogNotification = new PowerLogNotification();
        powerLogNotification.setUserId(userId);
        powerLogNotification.setAmount(power);
        powerLogNotification.setType(power > 0 ? PowerLogTypeEnum.PAY : PowerLogTypeEnum.EXPEND);
        powerLogNotification.setMark(power > 0 ? FundTypeEnum.INCOME : FundTypeEnum.EXPEND);
        powerLogNotification.setRemark(remark);
        notificationPublisher.publish(powerLogNotification);
    }

    @Override
    public void adminUpdateVidDateToUser(Long userId, Instant oldExpiredTime, Instant newExpiredTime) {
        if (oldExpiredTime == null) {
            oldExpiredTime = Instant.now();
        }
        String newSubDate = DateUtil.format(Date.from(newExpiredTime), DatePattern.CHINESE_DATE_PATTERN);
        PowerLogNotification powerLogNotification = new PowerLogNotification();
        powerLogNotification.setUserId(userId);
        powerLogNotification.setType(PowerLogTypeEnum.PAY);
        powerLogNotification.setMark(oldExpiredTime.isBefore(newExpiredTime) ? FundTypeEnum.INCOME : FundTypeEnum.EXPEND);
        powerLogNotification.setRemark(String.format(String.format("系统操作, 最新会员有效期至：%s", newSubDate)));
        notificationPublisher.publish(powerLogNotification);
    }

    @Override
    public void resetSubscribeToUserByDaily(Long userId, Integer vipDayPower) {
        UserProductLogEntity userProductLogEntity = new UserProductLogEntity();
        userProductLogEntity.setUserId(userId);
        userProductLogEntity.setProductType(ProductTypeEnum.SUBSCRIPTION_CARD);
        // 获取最新的一条有效的月卡记录
        Instant subsStartTime = Instant.now();
        Integer power = vipDayPower != null ? vipDayPower : ConfigUtil.getVipDefaultDayPower();
        userProductLogEntity.setPower(power);
        List<UserProductLogEntity> subscriptionCardList = getExpirationCardList(userId);
        // 如果有天卡记录，时间顺延即可
        if (CollectionUtils.isNotEmpty(subscriptionCardList)) {
            // 获取subscriptionCardList时间最大的一条记录
            subsStartTime = subscriptionCardList.stream()
                    .filter(subscriptionCard -> subscriptionCard.getProductType() == ProductTypeEnum.SUBSCRIPTION_CARD)
                    .map(UserProductLogEntity::getSubsEndTime)
                    .max(Instant::compareTo)
                    .orElse(Instant.now());
        }
        userProductLogEntity.setSubsStartTime(subsStartTime);
        userProductLogEntity.setSubsEndTime(subsStartTime.plus(1, ChronoUnit.DAYS));
        super.save(userProductLogEntity);

        PowerLogNotification powerLogNotification = new PowerLogNotification();
        powerLogNotification.setUserId(userId);
        powerLogNotification.setAmount(power);
        powerLogNotification.setType(PowerLogTypeEnum.PAY);
        powerLogNotification.setMark(FundTypeEnum.INCOME);
        powerLogNotification.setRemark("会员每日额度重置");
        notificationPublisher.publish(powerLogNotification);
    }

    // 获取最新的一条月卡记录
    @Override
    public List<UserProductLogEntity> getExpirationCardList(Long userId) {
        return list(Wrappers.<UserProductLogEntity>lambdaQuery()
                .eq(UserProductLogEntity::getUserId, userId)
                .ge(UserProductLogEntity::getSubsEndTime, Instant.now())
                .orderByDesc(UserProductLogEntity::getCreatedAt));
    }

    @Override
    public int getUserChatPower(Long userId) {
        // 获取套餐
        List<UserProductLogEntity> expirationCardList = getExpirationCardList(userId);
        expirationCardList = expirationCardList.stream()
                .filter(entity -> entity.getSubsEndTime() != null && entity.getPower() != null) // 过滤掉空值
                .toList();
        if (CollectionUtils.isEmpty(expirationCardList)) {
            return 0;
        }
        return expirationCardList.stream().map(UserProductLogEntity::getPower).reduce(0, Integer::sum);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void reducePower(Long userId, Integer power, AiPlatformEnum platform, Long historyItemId) {
        if (userId == null || power <= 0) {
            return;
        }
        // 获取套餐
        List<UserProductLogEntity> expirationCardList = getExpirationCardList(userId);
        expirationCardList = expirationCardList.stream()
                .filter(entity -> entity.getSubsEndTime() != null) // 过滤掉空值
                .filter(entity -> entity.getPower() > 0)
                .sorted(Comparator.comparing(UserProductLogEntity::getSubsEndTime))
                .toList();
        if (CollectionUtils.isEmpty(expirationCardList)) {
            return;
        }
        int chatCalls = power;
        for (UserProductLogEntity userProductLogEntity : expirationCardList) {
            if (userProductLogEntity.getPower() >= chatCalls) {
                userProductLogEntity.setPower(userProductLogEntity.getPower() - chatCalls);
                super.updateById(userProductLogEntity);
                break;
            } else {
                chatCalls -= userProductLogEntity.getPower();
                userProductLogEntity.setPower(0);
                super.updateById(userProductLogEntity);
            }
        }
        if (TransactionSynchronizationManager.isSynchronizationActive()) {
            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                @Override
                public void afterCommit() {
                    PowerLogNotification powerLogNotification = new PowerLogNotification();
                    powerLogNotification.setUserId(userId);
                    powerLogNotification.setAmount(power);
                    powerLogNotification.setType(PowerLogTypeEnum.EXPEND);
                    powerLogNotification.setMark(FundTypeEnum.EXPEND);
                    powerLogNotification.setPlatform(platform);
                    powerLogNotification.setHistoryItemId(historyItemId);
                    notificationPublisher.publish(powerLogNotification);
                }
            });
        }
    }

    @Override
    public void refundProductToUser(Long userId, Integer power, AiPlatformEnum aiPlatformEnum, Long historyItemId) {
        handlePower(userId, power);
        PowerLogNotification powerLogNotification = new PowerLogNotification();
        powerLogNotification.setUserId(userId);
        powerLogNotification.setAmount(power);
        powerLogNotification.setType(PowerLogTypeEnum.REFUND);
        powerLogNotification.setMark(FundTypeEnum.INCOME);
        powerLogNotification.setPlatform(aiPlatformEnum);
        powerLogNotification.setHistoryItemId(historyItemId);
        notificationPublisher.publish(powerLogNotification);

    }

    private void handlePower(Long userId, Integer power) {
        UserProductLogEntity userProductLogEntity = new UserProductLogEntity();
        userProductLogEntity.setUserId(userId);
        userProductLogEntity.setPower(power);
        userProductLogEntity.setProductId(-1L);
        userProductLogEntity.setOrderId(-1L);
        userProductLogEntity.setProductType(ProductTypeEnum.TIME_CARD);
        userProductLogEntity.setSubsStartTime(Instant.now());
        userProductLogEntity.setSubsEndTime(Instant.now().plus(36500, ChronoUnit.DAYS));
        super.save(userProductLogEntity);
    }
}
